package com.hzlj.position.locate.differentiation.sysCheck.powerOff;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fz.common.base.core.JsonUtils;
import com.google.common.collect.Lists;
import com.hzlj.common.message.common.dto.message.MessageNoticeResultDTO;
import com.hzlj.common.message.common.dto.phoneStatus.PhoneStatusQueryDTO;
import com.hzlj.common.message.common.dto.phoneStatus.PhoneStatusResultDTO;
import com.hzlj.common.message.common.util.PhoneStatusRestUtil;
import com.hzlj.position.config.common.dto.common.LocateTimerTask;
import com.hzlj.position.config.common.dto.common.PositionAddDTO;
import com.hzlj.position.locate.common.dto.differentiationConfig.DifferentiationConfigExtDTO;
import com.hzlj.position.locate.common.dto.differentiationData.DifferentiationDataAddDTO;
import com.hzlj.position.locate.common.dto.differentiationData.DifferentiationDataQueryResultDTO;
import com.hzlj.position.locate.common.dto.position.PositionKeyDTO;
import com.hzlj.position.locate.common.dto.positionSysCheck.PositionSysCheckExtDTO;
import com.hzlj.position.locate.common.enums.PositionSysCheck;
import com.hzlj.position.locate.converter.PositionSysCheckConverter;
import com.hzlj.position.locate.differentiation.common.PositionSysCheckHandle;
import com.hzlj.position.locate.differentiation.common.PositionSysCheckNoticeGzry;
import com.hzlj.position.locate.service.DifferentiationDataService;
import com.hzlj.position.locate.service.PositionSysCheckService;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static com.hzlj.position.config.common.enums.WarningType.POWER_OFF;


/**
 * 广东
 */
@Slf4j
@Service
public class PowerOffSysCheckGd extends PowerOffSysCheck {
    @Resource
    private PositionSysCheckNoticeGzry positionSysCheckNoticeGzry;
    @Resource
    private PositionSysCheckHandle positionSysCheckHandle;
    @Resource
    private PositionSysCheckService positionSysCheckService;
    @Resource
    private DifferentiationDataService differentiationDataService;

    /**
     * 是否需要重试
     */
    public Retry retry(LocateTimerTask.Task task,
                       PositionAddDTO position) {
        //需要重试的标记
        boolean retry;
        String key = task.key();
        DifferentiationConfigExtDTO config = this.getDifferentiationConfigExt();
        ReLocateCount reLocated = getLocateCount(key, config.getPowerOff().getTimes() - 1);
        PositionKeyDTO positionKey = new PositionKeyDTO(position.getId(), position.getPositionTime(), task.getKey().getJgCode());
        boolean hasPosition = ObjectUtil.isAllNotEmpty(position.getLatitude(), position.getLongitude(), position.getPosition());
        //首次
        if (!reLocated.hasRecord()) {
            if (!POWER_OFF.getCode().equals(position.getWarningType())) {
                return Retry.of(false);
            }
            retry = reLocated.incr(positionKey);
            saveLocateCount(key, reLocated);
        } else {
            int count = reLocated.getCount().get();
            retry = reLocated.incr(positionKey);
            saveLocateCount(key, reLocated);
            if (hasPosition) {
                retry = false;
            }

            //核查数据不需要处理
            position.setWarning(false);
            //数据类型
            position.setDataType(this.getType().getDataType());


            PositionKeyDTO oriPosition = reLocated.getPositionKeys().get(0);
            positionSysCheckService.savePositionSysCheck(getType(),
                    PositionSysCheckConverter.of(
                            task.getKey().getJzId(),
                            oriPosition,
                            positionKey,
                            "retry-" + count,
                            String.format(config.getPowerOff().getRetryStep(), count),
                            hasPosition,
                            hasPosition ? "成功" : "失败"
                    )
            );
        }

        //设置核查状态
        position.setSysCheck(PositionSysCheck.ING.getCheck());

        //等待分钟数据
        int count = reLocated.getCount().get();
        int minutes = config.getPowerOff().getDuration(count);

        //不需要再次重试了，则做处理，删除缓存
        LocateTimerTask.Task.Key taskKey = task.getKey();
        if (!retry) {
            this.handle(hasPosition, taskKey.getJzId(), taskKey.getDeviceCode(), taskKey.getJgCode(), reLocated.getPositionKeys(), minutes, count);
            removeLocateCount(key);
            differentiationDataService.removeLocateJobDelay(taskKey.getDeviceCode(), taskKey.getChannel());
        } else {
            differentiationDataService.setLocateJobDelay(taskKey.getDeviceCode(), taskKey.getChannel(), minutes);
        }

        log.info("系统核查[关机]:taskKey={},count={},retry={},minutes={},position={}", task.getKey(), count - 1, retry, minutes, positionKey);
        return Retry.of(retry, minutes);
    }

    private void handle(boolean locateSuccess,
                        String jzId,
                        String deviceCode,
                        String jgCode,
                        List<PositionKeyDTO> keys,
                        Integer minutes,
                        Integer count) {
        if (ObjectUtil.isEmpty(keys)) {
            return;
        }

        //考虑到入库是异步的，所以需要这样处理
        this.differentiationDataService.saveDifferentiationData(new DifferentiationDataAddDTO()
                .setType(this.getType().getDataType())
                .setHandleTime(DateUtil.offset(new Date(), DateField.MINUTE, minutes))
                .setServiceId(keys.get(0).getId())
                .setJzId(jzId)
                .setJgCode(jgCode)
                .setData(JsonUtils.obj2json(new DifferentiationData()
                        .setNormal(locateSuccess)
                        .setDeviceCode(deviceCode)
                        .setKeys(keys)
                        .setCount(count)
                ))
        );
    }


    @Override
    public void handleDifferentiationData(DifferentiationDataQueryResultDTO data) {
        DifferentiationConfigExtDTO config = this.getDifferentiationConfigExt();
        DifferentiationData differentiationData = JsonUtils.json2obj(data.getData(), DifferentiationData.class);
        boolean normal = differentiationData.isNormal();
        List<PositionKeyDTO> keys = differentiationData.getKeys();
        //原纪录
        PositionKeyDTO oriPosition = keys.get(0);
        List<PositionKeyDTO> sysPositions = keys.subList(1, keys.size());
        //需要做号码检测
        if (!normal) {
            PhoneStatusResultDTO phoneStatus = PhoneStatusRestUtil.phoneStatus(
                    new PhoneStatusQueryDTO(data.getJgCode(), null, differentiationData.getDeviceCode())
            );
            normal = phoneStatus.isNormal();
            //平台核查-电话核查
            positionSysCheckService.savePositionSysCheck(getType(),
                    PositionSysCheckConverter.of(
                            data.getJzId(),
                            oriPosition,
                            "phone_status",
                            String.format(config.getPowerOff().getRetryStep(), differentiationData.getCount()),
                            phoneStatus.isNormal(),
                            phoneStatus.getStatusMsg()
                    )
            );
        }
        //原纪录处理(只处理正常记录)
        if (normal) {
            positionSysCheckHandle.handleNormal(Lists.newArrayList(oriPosition), config.getPowerOff().getNormalRemark());
        } else {
            //不做处理，只更新系统核验标记
            positionSysCheckHandle.handleSysCheck(Lists.newArrayList(oriPosition), PositionSysCheck.FAIL);
        }
        //核查记录修改核查结果
        positionSysCheckHandle.handleSysCheck(
                sysPositions,
                normal ? PositionSysCheck.SUCCESS : PositionSysCheck.FAIL);

        Map<String, MessageNoticeResultDTO> notices = positionSysCheckNoticeGzry.notice(normal, oriPosition, getNoticeWorkerRoles());
        //平台核查-结果通知
        MessageNoticeResultDTO notice = notices.get(oriPosition.getId());
        positionSysCheckService.savePositionSysCheck(getType(),
                PositionSysCheckConverter.of(
                        data.getJzId(),
                        oriPosition,
                        "result_notice",
                        "结果通知工作人员",
                        notice != null && !notice.isFail(),
                        notice != null ? notice.getStatusMsg() : "通知异常"
                ).setSysCheckExt(notice == null ? null : new PositionSysCheckExtDTO()
                        .setMessageId(notice.getId() == null ? null : notice.getId().toString())
                        .setMessageServiceId(notice.getServiceId())
                        .setMessageTemplate(notice.getMessageTemplate())
                )
        );
    }

    @Data
    @Accessors(chain = true)
    public static class DifferentiationData {
        /**
         * 如果不正常，则需要做号码检测
         */
        private boolean normal;
        /**
         * 设备号
         */
        private String deviceCode;
        /**
         * 第几次
         */
        private Integer count;
        List<PositionKeyDTO> keys;
    }
}
